﻿using Basic.Oss.Interfaces;
using Basic.Oss.Options;
using Microsoft.Extensions.Options;
using Shared.Const.Enum.Oss;

namespace Basic.Oss.Implements;

/// <summary>
/// 本地磁盘OSS服务
/// </summary>
public sealed class LocalDiskOssService : IOssService
{
    private readonly LocalStorageOption _option;

    private EnumOssDir Dir { get; set; } = EnumOssDir.FileDir;

    private string _dirName;
    private string DirName { get => _dirName ??= Dir.GetEnumItem().TextName; }

    public LocalDiskOssService(IOptions<FileStorageOption> option)
    {
        this._option = option.Value.LocalStorage;
        if (_option == null)
        {
            throw new ArgumentNullException(nameof(FileStorageOption.LocalStorage));
        }
    }

    private string GetLocalFilePath(string ossFileName)
    {
        string fileUrl = Path.Combine(_option.LocalDisk, DirName, ossFileName);
        string filePath = Path.GetDirectoryName(fileUrl);
        if (!string.IsNullOrEmpty(filePath) && !Directory.Exists(filePath))
        {
            Directory.CreateDirectory(filePath);
        }
        return fileUrl;
    }

    public string GetFileUrl(string ossFileName) => string.Join('/',DirName, ossFileName);

    #region 读文件

    public Stream GetFileStream(string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        return File.Exists(localPath) ? new FileStream(localPath, FileMode.Open, FileAccess.Read) : Stream.Null;
    }

    public byte[] GetFileBytes(string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath))
        {
            using var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            return buffer;
        }
        else
            return Array.Empty<byte>();
    }

    public Task<Stream> GetFileStreamAsync(string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath))
        {
            Stream fs = new FileStream(localPath, FileMode.Open, FileAccess.Read);
            return Task.FromResult(fs);
        }
        else
            return Task.FromResult(Stream.Null);
    }

    public async Task<byte[]> GetFileBytesAsync(string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath))
        {
            using var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
            byte[] buffer = new byte[stream.Length];
            await stream.ReadAsync(buffer, 0, buffer.Length);
            return buffer;
        }
        else
            return Array.Empty<byte>();
    }

    #endregion

    #region 上传文件

    public bool PutFile(Stream stream, string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath)) File.Delete(localPath);

        if (stream.CanSeek)
            stream.Seek(0, SeekOrigin.Begin);

        using FileStream fs = new FileStream(localPath, FileMode.Create, FileAccess.Write);
        stream.CopyTo(fs);
        return true;
    }

    public bool PutFile(byte[] bytes, string fileUrl)
    {
        if (bytes == null || bytes.Length == 0)
            throw new ArgumentNullException("bytes");

        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath)) File.Delete(localPath);

        using FileStream fs = new FileStream(localPath, FileMode.Create, FileAccess.Write);
        fs.Write(bytes, 0, bytes.Length);
        return true;
    }

    public async Task<bool> PutFileAsync(Stream stream, string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath)) File.Delete(localPath);

        if (stream.CanSeek)
            stream.Seek(0, SeekOrigin.Begin);

        using FileStream fs = new FileStream(localPath, FileMode.Create, FileAccess.Write);
        await stream.CopyToAsync(fs);
        return true;
    }

    public async Task<bool> PutFileAsync(byte[] bytes, string fileUrl)
    {
        if (bytes == null || bytes.Length == 0)
            throw new ArgumentNullException("bytes");

        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath)) File.Delete(localPath);

        using FileStream fs = new FileStream(localPath, FileMode.Create, FileAccess.Write);
        await fs.WriteAsync(bytes, 0, bytes.Length);
        return true;
    }

    #endregion

    public bool DeleteFile(string fileUrl)
    {
        string localPath = GetLocalFilePath(fileUrl);
        if (File.Exists(localPath))
        {
            File.Delete(localPath);
            return true;
        }
        return false;
    }

    public Task<bool> DeleteFileAsync(string fileUrl)
    {
        bool success = DeleteFile(fileUrl);
        return Task.FromResult(success);
    }
}